{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "initial_id",
   "metadata": {
    "collapsed": true,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:07:10.796571Z",
     "start_time": "2024-11-07T02:07:09.738583Z"
    }
   },
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from langgraph.constants import START, END\n",
    "from langgraph.graph import StateGraph\n",
    "import operator\n",
    "from typing import Annotated, Any\n",
    "from typing_extensions import TypedDict\n",
    "from dotenv import load_dotenv\n",
    "import os\n",
    "from langchain_openai import ChatOpenAI\n",
    "\n",
    "load_dotenv()\n",
    "llm = ChatOpenAI(\n",
    "    openai_api_key=os.getenv(\"DASHSCOPE_API_KEY\"),\n",
    "    openai_api_base=\"https://dashscope.aliyuncs.com/compatible-mode/v1\",\n",
    "    model_name=\"qwen-max\",\n",
    "    temperature=0, streaming=True,\n",
    ")\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "\n",
    "\n",
    "class ReturnNodeValue:\n",
    "    def __init__(self, node_secret: str):\n",
    "        self._value = node_secret\n",
    "\n",
    "    def __call__(self, state: State) -> Any:\n",
    "        print(f\"ReturnNodeValue state: {state}\")\n",
    "        print(f\"Adding {self._value} to {state['aggregate']}\")\n",
    "        return {\"aggregate\": [self._value]}\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"d\")\n",
    "builder.add_edge(\"c\", \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "\n",
    "from IPython.display import Image, display\n",
    "\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))"
   ]
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ReturnNodeValue state: {'aggregate': []}\n",
      "Adding I'm A to []\n",
      "ReturnNodeValue state: {'aggregate': [\"I'm A\"]}\n",
      "Adding I'm B to [\"I'm A\"]\n",
      "ReturnNodeValue state: {'aggregate': [\"I'm A\"]}\n",
      "Adding I'm C to [\"I'm A\"]\n",
      "ReturnNodeValue state: {'aggregate': [\"I'm A\", \"I'm B\", \"I'm C\"]}\n",
      "Adding I'm D to [\"I'm A\", \"I'm B\", \"I'm C\"]\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'aggregate': [\"I'm A\", \"I'm B\", \"I'm C\", \"I'm D\"]}"
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "graph.invoke({\"aggregate\": []}, {\"configurable\": {\"thread_id\": \"foo\"}})\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:07:10.823509Z",
     "start_time": "2024-11-07T02:07:10.800431Z"
    }
   },
   "id": "9ebda81de17d3e3f",
   "execution_count": 11
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Parallel node fan-out and fan-in with extra steps\n"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "755fe148445c561f"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"b2\", ReturnNodeValue(\"I'm B2\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_edge(\"a\", \"b\")\n",
    "builder.add_edge(\"a\", \"c\")\n",
    "builder.add_edge(\"b\", \"b2\")\n",
    "builder.add_edge([\"b2\", \"c\"], \"d\")\n",
    "builder.add_edge(\"d\", END)\n",
    "graph = builder.compile()\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:07:11.658722Z",
     "start_time": "2024-11-07T02:07:10.827537Z"
    }
   },
   "id": "87c6713c527b35",
   "execution_count": 12
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Conditional Branching\n",
    "微调State"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "e50c9d18cc20aa10"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "image/jpeg": "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",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from typing import Sequence\n",
    "\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "    which: str\n",
    "\n",
    "\n",
    "def route_bc_or_cd(state: State) -> Sequence[str]:\n",
    "    print(f\"route_bc_or_cd state: {state}\")\n",
    "    if \"which\" in state and state[\"which\"] == \"cd\":\n",
    "        return [\"c\", \"d\"]\n",
    "    return [\"b\", \"c\"]\n",
    "\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.add_edge(START, \"a\")\n",
    "builder.add_node(\"b\", ReturnNodeValue(\"I'm B\"))\n",
    "builder.add_node(\"c\", ReturnNodeValue(\"I'm C\"))\n",
    "builder.add_node(\"d\", ReturnNodeValue(\"I'm D\"))\n",
    "builder.add_node(\"e\", ReturnNodeValue(\"I'm E\"))\n",
    "\n",
    "intermediates = [\"b\", \"c\", \"d\"]\n",
    "builder.add_conditional_edges(\n",
    "    \"a\",\n",
    "    route_bc_or_cd,\n",
    "    intermediates,\n",
    ")\n",
    "for node in intermediates:\n",
    "    builder.add_edge(node, \"e\")\n",
    "\n",
    "builder.add_edge(\"e\", END)\n",
    "graph = builder.compile()\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:07:12.647062Z",
     "start_time": "2024-11-07T02:07:11.664711Z"
    }
   },
   "id": "1c6392706d9b5e",
   "execution_count": 13
  },
  {
   "cell_type": "markdown",
   "source": [
    "## Stable Sorting\n",
    "根据node权重执行。通过增加node 权重，并排序sorting"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "c3a60164d6225cb7"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "image/jpeg": "/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAMCAgMCAgMDAwMEAwMEBQgFBQQEBQoHBwYIDAoMDAsKCwsNDhIQDQ4RDgsLEBYQERMUFRUVDA8XGBYUGBIUFRT/2wBDAQMEBAUEBQkFBQkUDQsNFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBT/wAARCAGwAOgDASIAAhEBAxEB/8QAHQABAAMAAwEBAQAAAAAAAAAAAAUGBwMECAIJAf/EAFUQAAEDAwICAwkJCQwKAwAAAAEAAgMEBREGEgchEzFBFBUWIjZRYZTRCBcyVVZ0k7LTGCM0VHJzdYGzJDU3QlJxlaGxtMHSCSUoM1NiZIKR1ISi4f/EABsBAQADAQEBAQAAAAAAAAAAAAABAgMFBAYH/8QANREBAAEDAAcFBwIHAQAAAAAAAAECAxEEITEzQXGRElFhscEFExQVUqHRIuEjMlNigZLwwv/aAAwDAQACEQMRAD8A/VNERAREQEREBERARFWqiqrdUVM1LbamS3W2B5inuEbWmSZ45OZCTkAA5DnkHmCG8wXN0oo7XhCU9VV1NQNDqmoip2nqMrw0H/yul4VWX44oPWWe1dKj4f6do3mUWimqKkkF1VWM7oneR1bpZNzz1nrPau74K2X4noPVmexaYsxxmekesmo8KrL8cUHrLPanhVZfjig9ZZ7U8FbL8T0HqzPYngrZfieg9WZ7E/g+P2TqPCqy/HFB6yz2p4VWX44oPWWe1PBWy/E9B6sz2J4K2X4noPVmexP4Pj9jUeFVl+OKD1lntTwqsvxxQess9qeCtl+J6D1ZnsTwVsvxPQerM9ifwfH7Gp3aWupq5hfTVEVQ0dbonhw/qXOq/V6A09VPEjbVT0lQMltVRN7nmaT1kSR4cOodvYF8UtZW6crKehudQ6voah4ipbi5gD2PI5Rz4wMk/BeAASQ0gO2mSOxTVu5190+n/QjHcsaIiwQIiICIiAiIgIiICIiAiIgIiICIiCC1xc57TpaumpHiOtkDKankIyGTSvbFG4j0Oe0qTtVsp7NbaWgpGdHTU0bYo25yQAMDJ7T6e1QfEZh8EqipAc4UM9NcHBrdxLYJ45nYHacRlWVrg5oc0ggjII7V6J1WY5z5R+6eD+oiLzoUziDxi0hwunoINS3Y0VTXCR9PTw0s1TK9jMb37IWPcGN3DLiA0Z5lVaX3Rllh44xcPXUdc4TWumrorhDb6uVj5Z5drIzthLWxhu1xmc7YC4tJBY4Kve6cpnUdZZ73YrZrGPXVDRVYs960rbTWxNcdh7lq2YLTFI4MPjtwNhO5p6+tDcNTaX456Z1XqTS11qO/miqO0Vklhon1kVFcW1LpZY5NmTHH99OHu8XxTzQaJR8ftBV+uPBCK/bb8amSiZDNRzxRSTx53xMmdGInvG13itcTyPJfP3QGhn6guljgulVW3W1zzU9bS0NqrKh1PJFGZHh/RxOAy0Haep5Ba3cQQvNd8t+s9RXzTlfqGza/ueq7Rrunr7hHHBMLJRW6Otc2N1LG0iOcdC6M7mB8nOQuIGVvnADT1bY7pxYmrrbUUDrhrWsqoJKiB0fdMBp6YMkYSBuYS1wDhkZB9KDve5+45UHHjQ1NfaahqrZVlgfU0k1LUMjiLnPDRHNJGxs3JnN0eQD14yFpyw/3JVRcLDwvtmh7zp+9WW9acjkpqqSvoXxUsx6aTDoJiNkrSMOy0nkVuCAulerTBfrTV2+pBMNTGY3Fpw5uepwI5gg4II5ggELur4llZBE+SRwZGxpc5x6gB1lWpmYmJjaIjRd3mvmlrbWVRaat0WyoLBhvStJZJj0bmuwppVrhzC+LRdtkka5jqoPrNjhhzemkdKAR2Eb+YVlWl6Ii7VFOzM+aZ2iIixQIiICIiAiIgIiICIiAiIgIiIPl7Gyscx7Q9jhgtcMgjzFVa21zNECG03KVsNrBEVvr5HHYG9TYZHHk14+C0k+MMfxsg2tcc8EdTC+GaNssUjS18b2hzXA9YIPWFrRXERNNWuJTEqfqfgtoHWt3kut/0ZYr1cpGtY+rr7fFNK4NGGguc0nAHJRZ9zZwoIAPDfSxA5DNpg5f/VWBvD6gpCO9tZcrPHnIgoqx4hHobG7cxo9DQAngTUfKq/fTQ/ZK/Ytzsr6x+MmId3SWidP6Ctr7dpuyUFhoJJTO+mt1OyCN0hABeWtAGSGtGfQFNqr+BNR8qr99ND9kngTUfKq/fTQ/ZJ7u39f2kxHetCLK47fdX8VqjTp1Tee90dlir2npIek6V08jDz6P4OGjs6881bPAmo+VV++mh+yT3dv6/tJiO92tX6C01xAo4KTU1ht1/pYJOlihuVKydjH4I3AOBwcEjPpVVHubeFDQ4DhvpYBwwQLTBzHX/J9AVg8Caj5VX76aH7JPAmo+VV++mh+yT3dv6/tJiO9waT4QaG0Hc33HTekLJYa98RhdVW6gigkMZIJaXNAOCWtOPQFyXCpj10JLXRFs9kJ2V9Y0ksnb2wREcnZ+C9w5AEt+ETs5Dw+t9VyudVcL1Hk5guFW58Ls9YdEMMcPQ5p/rKskUTIImRxsbHGwBrWNGA0DqACRNFvXROZ6Y/P2NUPoDAwOQX9RF50CIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgz2Aj7oGsGTu8F4OX/wAub0/4LQlnsGfugazqx4MQebP4XL+taEgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiDPIB/tB1p3DPgvByxz/AAuZaGs8gx90HW+fwXg7P+rm7VoaAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIqdUavutylldYaCjmoo3ujFXXVD4xM5rtrixrWOJZkEbiRnGQC0hx4e/usPxCx+tzfZr1xotzjiP8wnDxpb/AHfN3qvdEOtTeFNQ3Us7GaZNqdeWgsqG1LySX9z9WXEdXIDK/QJeaKb3P01L7oqo4vst9m78y0XQdx90SiJs+3Y6oB6P4Rjw3GOvLs5K2Dv7rD8Qsfrc32an4WvvjrBhd0VPo9X3SgqYW3630lPSTPbE2soah8oje44aJGuY0taSQNwJ5kZAHNXBYXLVVuf1GMCIiyQIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiDOeHB3aCsDj1miiJ/nLQrGq3w38gNPfMYvqhWRdm/va+c+aZ2yIiLFCu8QTjR9xI6w1hHoO9q0VZ1xC8jrl+S367VoqppG6o5z5UrcBERc9UREQEREBERAREQEREBERAREQEREBERAREQERfEsrIInyyvbHGxpc57zgNA6yT2BBnfDfyA098xi+qFZFW+GxDuH+niDkGhhwR+SFZF2b+9r5z5pnbLyFU6z1Cdd6Z1tpus1INKXbWbLI6e86gMtPWRSVEkEjYbf0e2ONrmu2P3tf8AewSDnK9erNn+5z4dyXZ9ydpxvdRrRcmYq6gRwVQkEvTQx9JsheXgEmMNJ5g5BIOkrzUxMbUK7xC8jrl+S367VoqzjiPKyHRN1kke2ONkbXOe44DQHDJJWjNc17Q5pDmkZBByCE0jdUc58qVuD+oiLnqiIiAiIgIiICIiAiIgIiICIiAiIgIiICKIvOp6Kzvlpg4112bSvrIrTSvY6rqI2lrSWRucMjc9jdxIaC4ZIXVltFzv0tQ251Xcdt6Wnmpqage+KcbAHSNmlDvGa5/LawAbWYLnB5aA7HhVR1Feyjt+btKKp9JUuonNkZRSMYHuE7s4jOHM8U+Md7cDGSOpSaaq7tDBNqaeKtnfRyUtTbKYHvc7pHZdmN+TIduGZecEBxDWbiFP09LDSRlkETIWF7pC2NoaC5zi5zsDtLiST2kkrlQZxw38gNPfMYvqhWRQkVrvOkou4KS0y3q3xE9zSU08TJWMJ5Me2V7QS3JG4HmAOQKd9r98jLr61RfbrtV4uVzXTVGJnO2I9VpjM5TaKsDVl2deHWwaNvPdbYBUkdJS7NhcWjx+m25yD4uc9uMFdzvtfvkZdfWqL7dU7H90f7R+TDr8RGh+jLm1wBaWNBB7fHarFU6cq7NDUzaamip5ugggp7ZVl3e+NsZAwxjecRMeWZZ4ow1xY7BBhu9d41YWUldaZLLbekZJO6pnjfLKGuDhG1sbnAAkc3F3VkAHORfV5tImIppozmYzOrXtx+CdmEPHqekbWupK0OtVQ6rNHTNri2MVj9hkHQnJEmWtccDxhsdkDCmFw1NJBWsY2ohjnax7ZWtlYHBr2kFrhnqIIBB7CFBR2u6abZTR2yY3K2QtqXzUtbI6Wre53jxNime8AAHczbJnk5vjtDMO8Kqxoou0ajorw5kDX9zXIU0VXNbKhzW1VOyTO0yRgkt5te3PMEscATgqUQEREBERAREQEREBERAREQERQV3v9QJqm22enFXeBSmoiNQ17KRp37AJJmtIBzuO0ZdhjuQ5IJarrqa3xskqqiKmjfIyFrpnhgc97g1jQT2ucQAOskgBQsFwu1/lpZaOI2m1iSojqTXwEVUoaNsboW7sMBdl+6QE7WgbPH3N7MOmoHV8tbXSPuc7po6iFtUA6KjeyPYDAzH3vO55Lslx6RwLsYAmEEfZbHS2Kihp6fpZXRxNhNTVSumnlDSSN8jiXOOXOPM9bj51IIiAiIgIiIK+ycHX00PdFyJFsY/oDH+4h99eNwdj/e9hGfghqsCrkdQ08RJ4O7K8uFqjf3IWfuQDpnjeHf8AEOMEfyQFY0BERAREQRl90/S6goZ6eZ09NJJH0baujldDURDcHeJI3Dh4zWnHUccwRyXTqLldbLVzurKU3O3TVUMNK+3REzU7HgNc6dpd4zWv572dTX82AMc8z6IOCjrqe4wCelnjqYS5zOkieHN3NcWuGR2hwII7CCFzqFqNNRxVkdZbJnWuoa+aWSKBrRT1ckjAC6dmPHILWO3Atf4uN2HOBWi/SyzxW66U3cV4bSR1EzYQ99KSXFrhFM5rQ/Dh1EBwDmEtG4IJpERAREQEREBERATqRVi/mm1LeTpeWS31VG6kM93tlVE6R81NJvjjbjIbse5kgdu3BzWObtIcSA7EdXXahrGOpHS262U1Th8z42uNxj6PIMRDiWR73AbyAXdG7aNrmvMnaLRR2G2U1ut9NHSUVMwRxQRDDWNHZ/8Aq7nUiAiIgIiICIiAiIgrkdYw8RJ6Tu+sMgtUcvcJj/cwBmeOkDv5ZxgjzAKxqusrc8QZqPu2sOLXHL3EYR3MMyvHSCTr3nGC3zAHtViQEREBERAREQF0rzZqLUFtnt9xpmVdHMAHxSDkcEEEHrBBAII5ggEEEBd1EED3ZX2GuLa6R9xt9XVSGOqbGyPuCPo9wbMcjc3c14DwARuja4HDnmeXxLEyeJ8cjGyRvBa5jhkOB6wQq7p+aCx3io002ahihhgZUWygpo3skgpA1sZa4ElpDZA7BbtAa5jdo27nBZUREBERARFC3jW2ntP1QprnfLdb6kjd0NTVMY/Hn2k5wr00VVzimMynGUnW1tPbaOerq54qWkp43SzTzPDGRsaMuc5x5AAAkk9WFnNk4xaLufESvpKbiFpiubU0dDDR26nrYDMZ3S1IOJA777vzG0RgktLScDpBmwz8S9E1UEkE+pLLNDI0sfHJVxOa5pGCCCeYI7F+fHCD3NGnNI+7Lrq+qvNuboHT84vNprH1bOjneXB1PC12ebonc3fmh1bgtfh730T0lPZnufpmiq3vpaO+VNo9dj9qlLLqqy6jMgtV2ork6P4baSoZIWebIBOP1qtVm7RGaqZiOSMSlURFigREQEREBFE3rVlk04+Nl1u9DbXyDLGVVQyNzh5wCclRnvpaO+VNo9dj9q2ps3a4zTTMxyTiVSZx24dHXUzffJshi72sIpzdKfuQO6V/jCTfgydhb17QD2rVl+Y9v9y7paH3ackz7naveyhlF/jmNTH0DvGyKPOSCRLyLevoxntX6H++lo75U2j12P2q3w976J6Snsz3LSii7Lqizaj6TvVdaK5GPG8UtQ2Qsz1ZAJx+tSixqpqonFUYlUREVQREQERRN61ZZNOPYy63ehtz3jcxlVUMjc4ZxkAnJCtTTVXOKYzJtSyyyp44aCbrijPvlaTZRC3VHSUpuFOXuk6WHa/pt2GgDcNmfG3A4O3lavfS0d8qbR67H7V+eGsfcvaYuvuz6aenutrHDW4y9/audlSwQwkOzJS5BABfJ1AfxX/8pW3w976J6St2Z7n6cIqt76WjvlTaPXY/apGz6xsOoZzBbL1QXCcN3mKmqWSPDfPgHOPSq1WLtMZqpmI5SjEphERYodK9VjrfZ66qYAXwQSStB87Wkj+xVHSVJHTWCikA3T1MTJ55nc3zSOaC57ieZJJ/V1dQVn1V5MXj5nN9Qqvaa8nLV80i+oF0LGq1PNPBJIiK6BQGsXCgoYbtEAytoqiF0UzeTtrpWNezPa1zSQQeXUcZAU+q9r/yVqfzsH7Zi1s67lMeK1O2GiIiLjqiIiAiIgzvRRbXWnvtKN9dXvfLNM7m53juDW5/ktAAA6hhWFV3h55G238l313KxLs3t5VHjKZ2iIixQgNXOFvpaa7RAMraOpg6OZvwtjpmNewnta5pIIPLqOMgLQlnevfJmX5xTf3iNaIs9I3dE+M+ieAiIvAgREQFneiC2usrLtIN9bcXOnnmd8J2XHa3PmaMNA6gByWiLOeHfkTaPzP+JXQ0fdVz4x6p4LGiIroFBa2haNM3Csb97q6GCSqppwPHhlYwlrmnl5sEZ5gkHkSp1QutvIy//o+o/ZuWtreU80xtXejnNVSQTEbTJG1+B2ZGUXFaf3qovzLPqhFyatUyh1tVeTF4+ZzfUKr2mvJy1fNIvqBWHVXkxePmc31Cq9pryctXzSL6gXvs7mefongkl5c4E8eNT2Thhw4n1lp6sqbDeXx21urZbsKqd1TLI5sTqiIjc1jnYaH73Y5ZAyvUa82aO4BcQYtGaH0JqS4abZpHT1XTV9RPbHVD6ytfBL0zIdr2NYxnSYy/JLg3k1ucCKs51Iek1Xtf+StT+dg/bMVhVe1/5K1P52D9sxemzvaecLU7YaIiIuMqIiICIiDOuHnkbbfyXfXcrEq7w88jbb+S767lYl2b+9q5z5pnbLKLDxj1BrbUNUNL6JN00nSXN9rnv1RdY6Zz3xydHNJDAWEyRscHDJc0u2naCtXWMaJ4e8ROF9xqrJp+q01XaJnu0txikuRqGV1JFPMZZoGsY0skwXv2PLm4yMg4wtnXnjPFCva98mZfnFN/eI1oizvXvkzL84pv7xGtEVdI3VHOf/KeAiIvAgREQFnPDvyJtH5n/ErRlnPDvyJtH5n/ABK6Gj7qvnHlUngsa8vcZ+OuptR8O9RV2kbBV0elqS701tZq6K7Cnme+OviimdDC1u50RcHRbt4JyfFIyvUK8z3jgFxGg0FeOHVmr9MT6NmuouFBVV0lRHXQRGubVugc1rHMOHbgH55jALR1hVngh6YULrbyMv8A+j6j9m5TShdbeRl//R9R+zcvRa3lPOExtXK0/vVRfmWfVCJaf3qovzLPqhFyav5pQ62qvJi8fM5vqFV7TXk5avmkX1ArTeaN1xtFdSMID54JIgT2FzSP8VUNJVkdRYaOEHZU00LIKiB3J8MjWgOY4HmCD/5GCORC91jXamPFPBMIiK6BV7X/AJK1P52D9sxWFQGrw240cNohcH11ZPCI4WnLtjZWOe8gdTWtBJJ5dQzkha2dVymfFanbDQkRFx1RERAREQZ1w88jbb+S767lYlXtF7aC196JXBlfQPfHNA7k4De4tfjta4EEEcufXyKsK7N7XcqnxTO0REWKFe175My/OKb+8RrRFnurQ2401NaIXCSuq6mAshacuDGzMc+QgdTWtBJJ5ZwM5cFoSz0jd0R4z6J4CIi8CBERAWc8O/Im0fmf8StGWd6J20FnZaJTsrreXQzQO5Obhx2ux2tcMEEcjldDR91XHjHqngsKIiugULrbyMv/AOj6j9m5TSgtbTsOm7hQtIkra+CSlpacHx5pXsIa0DmfSTjAAJPIFa2t5TzTG1dbT+9VF+ZZ9UIuWjgNLSQQk7jGxrM+fAwi5NWuZQ5lC3jRWn9Q1AqLpY7bcZwNolqqSOR4Hmy4E4U0iU11UTmmcSbFW96vRnyTsn9Hxf5VR7Nw60tJxr1bRP0/an0UNgs80VI6jiMcT31FyD3tbjkXCNgJwM9G3mdvLYVnxe62cfQHvxHetNARNJOC6jqiXY7M4rm+k47cHG3xF7656ynM96Y96vRnyTsn9Hxf5VK2XS9m04JBabTRWzpMb+5KdkW7zZ2gZUoirVeu1xiqqZjmZkREWKBERAREQRV60rZdSGM3a0UNzMYww1lMyUtHo3A4UX71ejPknZP6Pi/yq0otqb12iMU1TEc05ljsPDvS544VdCdPWo0I07DOKTuOLoxIamUF+3HwiABnHUBzV596vRnyTsn9Hxf5VDQk/dAVgz4vgxBy5/jcv6loSt8Re+uesmZ70ZZtM2fTjZBarVRW0SY39yU7It2OrO0DKk0RY1VTVOapzKBERVBERAUVetKWXUZYbtaKG5uYMMNXTMlLR5gXA4UqitTVVROaZxIq3vV6M+Sdk/o+L/KqNW8O9LN432ahbp61NoXadrppKQUcXRukFTSBry3HNwBeAccg48xnnsSz6hPfPjzdpWPDorRp6mp3AZ5SVFRK8g9mQ2njPn8cedbfEXvrnrKcz3pj3q9GfJOyf0fF/lUlZ9IWLTsrpbXZrfbZXN2mSkpmRuLevGWgHHoUuirVfu1RiqqZjnJmRERYoEREBUbipaqwUdo1LaqeSqumnKwVwpoWlz6qmcx0dTC0Dm5xie5zW9skcavKIOpabrR321Udyt1THWW+shZUU9TC7cyWN7Q5j2ntBBBB9K7aoFTT1HC2snraKCet0hUSPnq6OBpkltbzzdLBG0Fz4XHcXRtyWk7mggkC7Wy50d6t9NX2+rgr6GpjbNBVU0gkilY4Za5rmkhwI5gjkUHZREQEREBERAREQZ7AD90DWHZy8F4Bv5/jcvLzLQlnkDT90FWu2nHgvAN3Z+FzcloaAiIgIiICIiAiLp3e70NgtlTcbnWQW+30zDLPVVMgjjiaOtznHkAg/l7vVDpyz1t1uVSyjt9HC6eonk+DGxoy4n9Q7FVuFVmrqW0XC93eB9NetRVjrnU00nwqZha2OCA+YxwxxNcBy39IR8JcNDS1fEq4U10uNNU2/TFLKyot9tqWOhmrZG821FTE4BzGtO10cTsEEB7wHBrWXxAREQEREBERAREQFRrnoW4WG4VV50VVQ0NZUPM1VZKxxbba6QnLnna1zqeU88yxgglxL45SG4vKIKlpniRb75dO8lfDNp/U7YzI6zXHDZZGjG6SBwJbPGMjL4y4NyA7aThW1ROptKWnWVrNvvNDHX0u8SNa/IdFIPgyRvBDmPb1h7SHA9RCqZptYcP9zqV8uutPsaNtJM5rLvTgYB2yuLY6kY7H7H8jl8hIADQkUFpTW1l1pTzyWmtbNLTOEdVSStdFU0jyMhk0LwHxOxz2vAOOfUp1AREQEREGewgfdA1h5Z8GIPPn8Ll/UtCX55W33SvHGp92DJod2n9KR6hc5tkll7gqjC2iZI6bukN7oBPiOL85xjAxlfoagIiICIiAigNV65s2jIqfvnVbaqqLm0lBTsdNVVbgMlsMLAXvIHXgchzOBzVd736v4gbXXGWXRFge07rdSStddZwcj75UMJZTjH8WEvf1ESt5hBKaj4i0dpuzrHbKabUOpuj6QWqhIzC0glr6iQ+JAw45F5y7B2NeRhdS06DrbvcqW96zq4bpc6Z4lpLZSbhbre8HIcxjuc0o5ffpBkYyxsW5wNj01pa0aOtTLbZbfBbaJrnSGKBuN73HLnvPW97jzc9xLnEkkkqVQEREBERAREQEREBERAREQEREFZ1Xw9tGraiGumbNb73TsMdLerc/oa2nbnO1sgHNhIBMbw5jseM0qCdqbVGgBt1NRO1LZGYAv1lpyamIY5mpo2gnA/4kBfkkkxRtGVoaIOjZL7btS2uC5Wmup7lb5xuiqaWUSRvGcHDhy5EEeghd5Uu9cMaSW61F709WS6V1DOd89ZQNBhrHcvwmnP3uY4AbvIEgHJr2rwTpn/SM3N3unG1d5qqd3DqSNtke2h6ZtOWtkdtuTY5DuY5znEluMiPaw7nM3EPdVPcb1q2nbcqe8T2SgqBvpIKSCJ0hiONr5HSsf4zhzwAAA4DmRuP13nvvy0vHq1D/AOuutw1/g50t+iqX9i1WRdquYt1zRTTGInGyPwtM4nDPY+DlLFxCl1yy+3Fuq5aIW59y6Cj3mAO3Bu3oNuc/xsbscs45Kz95778tLx6tQ/8ArqbRU95/bH+tP4RlByXK8aSYK6qu817t7HNFTHVwxMkYwnBex0TGjLc5II5gHmCr+s44kuazQV+c4hrRSPJJPIDC8Nj/AEhF6vXurGTWm4UtDw/q8WClZd5Hijga+RmLjK0PYNweNxLiMRFzcg+MvPpERNFNeNczMatWzHdzTOzL9G77qC2aYtktwu9fT22hjIDp6mQMbknAGT1knAAHMk4CpjdQar4gHbYKOXSdieD/AK7u9PiumHYaekePvY/56gAgj/cuBDlI2DhlSUNyivN8rajVWoozujuFyDdlMcEYpoGgRwDBIy0b3DAe955q5LwKq3pPh9ZtHyz1VLFJV3apaGVV4r5DUVtSASQHyu57QSSIxhjc4a1o5KyIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAq9ceHmlbxNLNX6Zs9bLK4ukkqaCKRzyeZJJackqwogzjhr/Bzpb9FUv7FqsirfDX+DnS36Kpf2LVZF2b+9r5z5pnbIi8N8LtFV/Ei2UGprhrfSun9fyXtzauqqKWo7901WyqINJuNa1paWt2CLothY4Yb2r3IvPTOUK3xJaH6CvzXAOaaR4IPUeSs9u4e6Vs80c1Bpqz0UsTg5klNQRRuYRzBBDRgqs8R/IS+/NX/wBi0ZRpG6o5z5UrcBERc9UREQEREBERAREQEREBERAREQEREBERAREQEREGccNf4OdLfoql/YtVkVc4bt28PNMNOMttdM04OeYiaCrGuzf3tfOfNM7ZQD+H+l5NSDUL9N2h1/GMXV1BEaoYGB9927ur0qfRFghXOI/kJffmr/7FoyzniKC7Q17aOt1M4D0k9S0ZV0jdUc58qVuAiIueqIiICIiAiIgIiICIiAiIgIiICIiAiIgIiICIiCnTaPuttfIyxXGkgoXuc9tJXUzpRCXHJDHNe0hmckNIOM4BDQGji7w6w+M7H6jN9srsi9caVc44n/EJyylldq5+vptMd02UPjtjLl3T3JNgh0r49m3pesbM5z2qwd4dYfGdj9Rm+2XSgcPugq1uOfgvAc8vxuZaGp+Kud0dIMqfS6PulwniN+uNJU0cT2yCjoaZ0Qle05b0jnPcS0EA7QBkjmSCWq4IiwuXarn8xnIiIskCIiAiIgIiICIiAiIgIiICIiAiIgIiICIiAiIgIiIM9gP+0DWDdy8F4DtyfxuXmtCWeQPP3QVa3sGl4D1/9XMtDQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERBnkGPug63qz4LwefP4XN+paGvKFL7tHg9Nx0mqWaulfDNaIbVHG20V5e6rFVITGI+g3Zw5vPHoXq9AREQEREBERAREQEREBERAREQEREBERAREQEREBEVB4p69l0xTQW22va28VjS8SkB3c0QIDpMHkXEnDQeWck5DS072LNekXItW9sib1NxBsGkZBDca8NqnDIpYGOmmIPUdjASAfOcD0qrP4+WUHxLRepB5xTxj+oyArIooWxF7sufJI4vklkcXPkcetznHm4nznmvtfY2/Yuj00/rmZnp/3UzDWPf9s/xLe/oYftU9/2z/Et7+hh+1WTotvk+id09TteDLbdwg0xRe69m4qd6bgdN4Nyhtggj6RtzPIux0mNgOZQQc7sDGOa9Ve/7Z/iW9/Qw/arJ0T5PondPU7Xg1j3/bP8S3v6GH7VfUfHuyOPj2m9RDONzqeM/VkJWSonyfRO6ep2vB6F0zr6w6vc6O2V7ZKhg3PpZWOimaPPseA7HpAx6VYV5WkhD5IpAXRzxO3xTRu2yRO7HNcOYPpC3DhdryTVdFPRXBzO/FCGmV7G7RPG7IbIB2HkQ4DkCM8g4BcH2h7L+Fp97anNPHO2DbsXlERfPgiIgIiICIiAiIgIiICIiAiIgIiIC8568rHXDiFqGV5JEMsdLGCfgsZE04H/AHPef1r0YvP3FC0vs3ECukcMQ3VjKyE45FzWNikaP5trCfzgX0PsSaY0iqJ2zE46x6J4SrSLp3m4S2q2zVUFvqrpLHjFJRmPpZMkDxekexvLOTlw5A9Z5KsjiBdPkBqYf91B/wC0vs6q4pnE+Us1outyhs1rrLhUktp6SF88pAyQ1rS4/wBQWL6T45aiv1zsE77Q2e13ieKPuSmtFwZNRRyfAlfUvjEMgblu7btGCSCQOegx6pq7+42yt0Nf6ajrAYJpap1H0TWOGHF2ypc7GD2AldHQ/Dy/6Kfb6BusJK7TVvaY6a3S2+MTdFtLWRvn3eMGZGMNafFGThea5Ny5XT7uZxx1fnHqlVbVxa1bJZbRqStpbN3iqr4bPLTwMlFSGmrdTNmDy7aMOAyzacjJ3DOBB8X9Y6m1pw44iTWqC1U2lbb3RbXuqxI6rqnRENlewtO1jQ7IAIdu2nqyr9Fwe6LQVBprvvnuW8C7d1dzfCxWmq6Pbv5dezdn047FE6l4GXO50WqrVadXG06f1FLLU1Fvltzah0U0mDI6OQvaQ1zhktx2nBGV5a7ekTb7M5nMd8bceQ1il/BYfyB/YuVVCfWtyoJ5KZmh9RVbIXGNtRC6iDJQDgObuqQcHGRkA8+YC+Xa+ujTgaB1K7kDkOoPN1fhS6PvaY7+k/hC4qe4c1r6DiRYSwkNq+no5OfW0wul/X40LVVrRXy3O3Q1M1BU2yWQEmkqyzpY+ZHjbHObzxnk49aunCe0Ou/ECmqQMwWiF9Q9/mlkaY2N/W10p/UPOsNMqpjRbk1bOzP3jV91qdrfURF+aJEREBERAREQEREBERAREQEREBERAUBrTR9LrS0Gjne6nnYekp6pgy6F/nx2g9Rb2g9hwRPor0V1WqoronEwPMmorJc9HyvZeqN9NC04bXMBfTSDzh4+B/M/af5xzUQ28297dza6mcD2iZvtXrJdCWwWud5fJbaSRx63OgaT/YvqLft3FOLlvM+E+mPUxDy733ofx2n+lb7U770P47T/AErfavT/AINWj4qovV2exPBq0fFVF6uz2Lb57b/pz1/YxDzB33ofx2n+lb7U770P47T/AErfavT/AINWj4qovV2exPBq0fFVF6uz2J89t/056/sYh5g770P47T/St9qOvNA0ZNdTAeczN9q9P+DVo+KqL1dnsX3FYbZTvD4rdSRuH8ZkDQf7E+fW/wCnPX9jEPOum7DdNZysZZqR8tO4+NcJmllMwecOP+8/mZnsyWjmt+0jpSk0dZ20NKXSuLjJNUSY3zSHrc7H8wAHYAB2KbRcTTfaNzTP04xT3flPIREXJQIiICIiAiIgIiIP/9k=",
      "text/plain": "<IPython.core.display.Image object>"
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ReturnNodeValue state: {'aggregate': []}\n",
      "Adding I'm A to []\n",
      "route_bc_or_cd state: {'aggregate': [\"I'm A\"]}\n",
      "state:{'aggregate': [\"I'm A\"], 'fanout_values': [], 'which': 'bc'}\n",
      "Adding I'm B to [\"I'm A\"] in parallel.\n",
      "state:{'aggregate': [\"I'm A\"], 'fanout_values': [], 'which': 'bc'}\n",
      "Adding I'm C to [\"I'm A\"] in parallel.\n"
     ]
    },
    {
     "data": {
      "text/plain": "{'aggregate': [\"I'm A\", [\"I'm B\"], [\"I'm C\"], \"I'm E\"],\n 'fanout_values': [],\n 'which': 'bc'}"
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "def reduce_fanouts(left, right):\n",
    "    if left is None:\n",
    "        left = []\n",
    "    if not right:\n",
    "        # Overwrite\n",
    "        return []\n",
    "    return left + right\n",
    "\n",
    "class State(TypedDict):\n",
    "    # The operator.add reducer fn makes this append-only\n",
    "    aggregate: Annotated[list, operator.add]\n",
    "    fanout_values: Annotated[list, reduce_fanouts]\n",
    "    which: str\n",
    "\n",
    "class ParallelReturnNodeValue:\n",
    "    def __init__(\n",
    "        self,\n",
    "        node_secret: str,\n",
    "        reliability: float,\n",
    "    ):\n",
    "        self._value = node_secret\n",
    "        self._reliability = reliability\n",
    "\n",
    "    def __call__(self, state: State) -> Any:\n",
    "        print(f\"state:{state}\")\n",
    "        print(f\"Adding {self._value} to {state['aggregate']} in parallel.\")\n",
    "        return {\n",
    "            \"fanout_values\": [\n",
    "                {\n",
    "                    \"value\": [self._value],\n",
    "                    \"reliability\": self._reliability,\n",
    "                }\n",
    "            ]\n",
    "        }\n",
    "\n",
    "def aggregate_fanout_values(state: State) -> Any:\n",
    "    # Sort by reliability\n",
    "    ranked_values = sorted(\n",
    "        state[\"fanout_values\"], key=lambda x: x[\"reliability\"], reverse=True\n",
    "    )\n",
    "    return {\n",
    "        \"aggregate\": [x[\"value\"] for x in ranked_values] + [\"I'm E\"],\n",
    "        \"fanout_values\": [],\n",
    "    }\n",
    "\n",
    "builder = StateGraph(State)\n",
    "builder.add_node(\"a\", ReturnNodeValue(\"I'm A\"))\n",
    "builder.add_edge(START, \"a\")\n",
    "\n",
    "builder.add_node(\"b\", ParallelReturnNodeValue(\"I'm B\", reliability=0.9))\n",
    "\n",
    "builder.add_node(\"c\", ParallelReturnNodeValue(\"I'm C\", reliability=0.1))\n",
    "builder.add_node(\"d\", ParallelReturnNodeValue(\"I'm D\", reliability=0.3))\n",
    "\n",
    "builder.add_node(\"e\", aggregate_fanout_values)\n",
    "\n",
    "intermediates = [\"b\", \"c\", \"d\"]\n",
    "builder.add_conditional_edges(\"a\", route_bc_or_cd, intermediates)\n",
    "\n",
    "for node in intermediates:\n",
    "    builder.add_edge(node, \"e\")\n",
    "\n",
    "builder.add_edge(\"e\", END)\n",
    "graph = builder.compile()\n",
    "display(Image(graph.get_graph().draw_mermaid_png()))\n",
    "config = {\"configurable\": {\"thread_id\": \"3\", \"user_id\": \"2\"}}\n",
    "\n",
    "graph.invoke({\"aggregate\": [], \"which\": \"bc\", \"fanout_values\": []},config)\n"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:09:32.505041Z",
     "start_time": "2024-11-07T02:09:31.355726Z"
    }
   },
   "id": "36fd53f55bc36d31",
   "execution_count": 17
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "No checkpointer set",
     "output_type": "error",
     "traceback": [
      "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m",
      "\u001B[0;31mValueError\u001B[0m                                Traceback (most recent call last)",
      "Cell \u001B[0;32mIn[18], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m graph\u001B[38;5;241m.\u001B[39mget_state(config)\n",
      "File \u001B[0;32m/opt/anaconda3/envs/ai_312/lib/python3.12/site-packages/langgraph/pregel/__init__.py:618\u001B[0m, in \u001B[0;36mPregel.get_state\u001B[0;34m(self, config, subgraphs)\u001B[0m\n\u001B[1;32m    614\u001B[0m checkpointer: Optional[BaseCheckpointSaver] \u001B[38;5;241m=\u001B[39m config[CONF]\u001B[38;5;241m.\u001B[39mget(\n\u001B[1;32m    615\u001B[0m     CONFIG_KEY_CHECKPOINTER, \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mcheckpointer\n\u001B[1;32m    616\u001B[0m )\n\u001B[1;32m    617\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m checkpointer:\n\u001B[0;32m--> 618\u001B[0m     \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mValueError\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNo checkpointer set\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m    620\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m (\n\u001B[1;32m    621\u001B[0m     checkpoint_ns \u001B[38;5;241m:=\u001B[39m config[CONF]\u001B[38;5;241m.\u001B[39mget(CONFIG_KEY_CHECKPOINT_NS, \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m    622\u001B[0m ) \u001B[38;5;129;01mand\u001B[39;00m CONFIG_KEY_CHECKPOINTER \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;129;01min\u001B[39;00m config[CONF]:\n\u001B[1;32m    623\u001B[0m     \u001B[38;5;66;03m# remove task_ids from checkpoint_ns\u001B[39;00m\n\u001B[1;32m    624\u001B[0m     recast_checkpoint_ns \u001B[38;5;241m=\u001B[39m NS_SEP\u001B[38;5;241m.\u001B[39mjoin(\n\u001B[1;32m    625\u001B[0m         part\u001B[38;5;241m.\u001B[39msplit(NS_END)[\u001B[38;5;241m0\u001B[39m] \u001B[38;5;28;01mfor\u001B[39;00m part \u001B[38;5;129;01min\u001B[39;00m checkpoint_ns\u001B[38;5;241m.\u001B[39msplit(NS_SEP)\n\u001B[1;32m    626\u001B[0m     )\n",
      "\u001B[0;31mValueError\u001B[0m: No checkpointer set"
     ]
    }
   ],
   "source": [
    "graph.get_state(config)"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-11-07T02:09:37.909695Z",
     "start_time": "2024-11-07T02:09:37.882840Z"
    }
   },
   "id": "2d89c36a3c2323c6",
   "execution_count": 18
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
